import java.util.ArrayList;
import java.util.Random;

/**
 * @author Simon
 * The frame to support PSO work.
 */
public class ParticleSwarm {
	Data trainData;
	int particleNumber  = 0;
	Particle[] particles;
	Network bestPosition;
	int iteration = 0;
	final int iterationMax = 10;
	double bestValue = 0;
	int bestNotChangedTimes = 0;
	/**
	 * The end condition for PSO iteration
	 */
	final int bestNotChangedTimesThreshold = 5;
	
	
	public ParticleSwarm(Data trainData, int particleNumber, int inputLayerNumber, int hiddenLayerNumber, int outputLayerNumber){
		this.trainData = trainData;
		this.particleNumber = particleNumber;
		particles = new Particle[particleNumber];
		for (int i = 0; i < particleNumber; i++){
			Particle particle = new Particle(this.trainData, inputLayerNumber, hiddenLayerNumber, outputLayerNumber);
			particles[i] = particle;
		}
		bestPosition = getBestParticle(particles).bestPosition.clone();
	}
	
	Particle getBestParticle(Particle[] particles){
		double max = getValueOfParticle(trainData, particles[0]);
		int maxi = 0;
		for (int i = 1; i < particles.length; i++){
			double value = getValueOfParticle(trainData, particles[i]);
			if (value > max){
				max = value;
				maxi = i;
			}
		}
		bestValue = max;
		return particles[maxi];
	}
	
	/**
	 * Evaluate position of this particle by the accuracy of the position network.
	 * This method is naive and time consuming, remain to be improved further.
	 * @param trainData current dataset.
	 * @param position the network which stand for current position.
	 * @return the accuracy of the dataset.
	 */
	double getValueOfParticle(Data trainData, Particle particle){
		return trainData.calMisRecord(particle.bestPosition);
	}
	
	public void update(){
		bestNotChangedTimes++;
		for (int i = 0; i < particleNumber; i++){
			particles[i].updateW(iteration, iterationMax);
			particles[i].updateVelocity(bestPosition);
			particles[i].updatePostion();
			if (particles[i].bestChanged){
				double value = particles[i].particleBestValue;
				if (value > bestValue){
					bestPosition = particles[i].bestPosition;
					bestValue = value;
					bestNotChangedTimes = 0;
				}
			}
		}
		iteration++;
		System.out.println(iteration + " : " + bestValue);
	}
	
	boolean isIteratoinEnd(){
		if (bestNotChangedTimes > bestNotChangedTimesThreshold){
			return true;
		}
		return false;
	}
}
